package dbops

import (
	"database/sql"
	"fmt"
	"log"
	"time"
	"video_server/api/defs"
	"video_server/api/utils"
)

// ----------- 用户操作 ---------------

// 打开连接
//func openConn() *sql.DB {
//	// 打开数据连接信息
//	db,error := sql.Open("mysql", "root:root@tcp(localhost:3306)/video?charset=utf8")
//	// 如果存在错误，就直接抛出异常
//	if error != nil {
//		panic(error.Error())
//	}
//	return db
//}

// AddUserCredential 添加用户
func AddUserCredential(loginName string, pwd string) error {
	// 使用预编译SQL的方式，进行执行
	stmIns, err := dbConn.Prepare("insert into users (login_name, pwd) values (?,?)")
	if err != nil {
		return err
	}

	// 把参数进行设置，会代替上面的 ？号
	_, exErr := stmIns.Exec(loginName, pwd)

	// 如果这里出现错误，下面的 Close() 方法则不会执行， 所以下面 Close() 方式要使用 defer 关键字
	if exErr != nil {
		log.Printf(exErr.Error())
		return exErr
	}
	// 关闭
	defer stmIns.Close()
	return nil
}

// GetUserCredential 获取用户的凭证，也就是密码
func GetUserCredential(loginName string) (string, error) {
	stmtQuery, err := dbConn.Prepare("select * from users where login_name = ?")
	if err != nil {
		log.Printf("%s", err)
		return "", err
	}

	var pwd string
	// 把参数进行设置
	row := stmtQuery.QueryRow(loginName)
	// Scan 获取一行中的哪一个字段的值, 在这里只获取 pwd 字段的值, 建议传指针进去
	// 查询出来的结果集，不scan会导致连接不释放
	err = row.Scan(&pwd)
	fmt.Printf("用户凭证是: %s", pwd)
	// 如果错误不为 nil, 并且err错误是 ErrNoRows 类型(结果集没有数据行)
	// 就把这个错误信息 return 回去
	if err != nil && err != sql.ErrNoRows {
		log.Printf("%s", err)
		return "", err
	}

	defer stmtQuery.Close()
	return pwd, nil
}

// DeleteUser 删除用户
func DeleteUser(loginName string, pwd string) error {
	stmtDel, err := dbConn.Prepare("delete from users where login_name = ? and pwd = ?")
	if err != nil {
		log.Printf("%s", err)
		return err
	}

	// 设置参数
	_, err = stmtDel.Exec(loginName, pwd)
	if err != nil {
		return err
	}

	defer stmtDel.Close()
	return nil
}

// ----- 视频操作 -----

// AddNewVideo 添加视频
func AddNewVideo(aid int, name string) (*defs.VideoInfo, error) {
	uuid := utils.NewGoUUID()

	// 获取本地最新时间
	t := time.Now()
	// 时间格式化，Go语言中时间格式化是使用时间模板
	// 这个时间是视频的 显示在页面上的创建时间
	// 目前使用的时间模板: M D y, HH:MM:SS
	ctime := t.Format("Jan 02 2006, 15:04:05")
	stmInsert, err := dbConn.Prepare(`insert into video_info (id,author_id,name,display_ctime) values(?,?,?,?)`)
	if err != nil {
		return nil, err
	}

	// 如果在上面定义了 err，在下面只接收 err 的话可以直接用 ”=“
	_, err = stmInsert.Exec(uuid, aid, name, ctime)
	if err != nil {
		return nil, err
	}

	// 创建一个 videoInfo, 并返回
	res := &defs.VideoInfo{Id: uuid, AuthorId: aid, Name: name, DisplayCtime: ctime}

	defer stmInsert.Close()
	return res, nil
}

// GetVideoInfo 查询视频
func GetVideoInfo(vid string) (*defs.VideoInfo, error) {
	var (
		aid  int
		name string
		dct  string
	)

	// 使用预编译SQL方式
	stmQuery, err := dbConn.Prepare("select author_id,name,display_ctime from video_info where id = ?")
	if err != nil {
		return nil, err
	}

	// 获取其中的一行数据, 并把查询条件设置上去
	// 取出插叙出来的值的
	err = stmQuery.QueryRow(vid).Scan(&aid, &name, &dct)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}

	// 如果错误是 sql.ErrNoRows 返回 nil
	if err == sql.ErrNoRows {
		return nil, nil
	}

	defer stmQuery.Close()

	res := &defs.VideoInfo{Id: vid, AuthorId: aid, Name: name, DisplayCtime: dct}
	return res, nil

}

// DeleteVideoInfo 删除视频
func DeleteVideoInfo(vid string) error {
	// 使用预编译SQL方式
	stmDelete, err := dbConn.Prepare("delete from video_info where id = ? ")
	if err != nil {
		return err
	}

	// 设置值
	_, err = stmDelete.Exec(vid)
	if err != nil {
		return err
	}

	defer stmDelete.Close()
	return nil
}

// ---- 评论操作 ----

// AddNewComments 添加评论
func AddNewComments(vid string, aid int, content string) error {

	uuid := utils.NewGoUUID()

	// 使用预编译SQL方式
	stmInsert, err := dbConn.Prepare("insert into comments (id,video_id,author_id,content) values (?,?,?,?)")
	if err != nil {
		return err
	}

	// 设置值
	_, err = stmInsert.Exec(uuid, vid, aid, content)
	if err != nil {
		return err
	}

	defer stmInsert.Close()
	return nil

}

// ListComments 评论列表
func ListComments(vid string, from, to int) ([]*defs.Comment, error) {
	// 使用预编译SQL
	stmQuery, err := dbConn.Prepare(`select comments.id, users.login_name, comments.content from comments 
		inner join users on comments.author_id = users.id
		where comments.video_id = ? and comments.time > form_unixtime(?) and comments.time <= from_unixtime(?)`)

	// 需要返回发切片
	var res []*defs.Comment

	// 设置查询参数
	rows, err := stmQuery.Query(vid, from, to)
	if err != nil {
		return res, nil
	}

	// 变量结果集
	for rows.Next() {
		var id, loginName, content string

		// 获取参数，并且判断是否有错误
		if err := rows.Scan(&id, &loginName, &content); err != nil {
			return res, err
		}

		c := &defs.Comment{Id: id, VideoId: vid, Author: loginName, Content: content}

		// 使用 Go 内置函数进行添加
		res = append(res, c)
	}

	defer stmQuery.Close()
	return res, nil

}
